"""
Case Type   : 资源池化
Case Name   : 资源池化场景下，开启事务内写转发&备机支持缓存快照信息，主节点dn挂起
Create At   : 2024.5
Owner       : haomeng802
Description :
    1、查看集群状态 cm_ctl query -Cv
    2、开启事务内写转发&备机支持缓存快照信息，重启集群
    3、设置dn僵死重启时间
        cm_ctl set xxx instance_phony_dead_restart_interval="10"
        cm_ctl reload --param --server
    4、主节点dn进程挂起（kill方式）
        ps ux | grep -v grep | grep bin/gaussdb | awk '{print $2}' | xargs kill -19
    5、再次查看dn进程,观察CMS服务是否会自动拉起恢复dn,查看集群状态
    6、恢复集群原始状态
        cm_ctl start,cm_ctl switchover -a
Expect      :
    1、集群状态正常，数据库节点状态正常
    2、参数配置成功，集群重启成功
    3、僵死重启时间设置成功
    4、挂起主节点dn进程成功
    5、dn进程存在,被拉起恢复（僵死检测耗时每次检测间隔约为36s）
    6、恢复集群成功，集群状态正常
History     :
"""

import os
import time
import unittest

from testcase.utils.ComThread import ComThread
from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node
from yat.test import macro

Primary_SH = CommonSH('PrimaryDbUser')


@unittest.skipIf(3 != Primary_SH.get_node_num(), '非1+2环境不执行')
class SharedStorage(unittest.TestCase):

    def setUp(self):
        self.log = Logger()
        self.log.info(f'-----{os.path.basename(__file__)} start-----')
        self.constant = Constant()
        self.com = Common()
        self.usernode = Node('PrimaryDbUser')
        self.param = 'instance_phony_dead_restart_interval'
        self.remote_excute = 'enable_remote_excute'
        self.bcast_snapshot = 'ss_enable_bcast_snapshot'
        self.remote_excute_default = self.com.show_param(self.remote_excute)
        self.bcast_snapshot_default = self.com.show_param(self.bcast_snapshot)

    def test_shared_storage(self):
        text = '-----step1:查看集群状态; expect:集群状态正常-----'
        self.log.info(text)

        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cv')
        self.log.info(status)
        self.assertIn('cluster_state   : Normal', status, '执行失败' + text)

        text = '----step2:开启事务内写转发&备机支持缓存快照信息,重启集群; expect:参数设置成功,集群重启成功----'
        self.log.info(text)

        set_param1 = Primary_SH.execute_gsguc('set',
                                              self.constant.GSGUC_SUCCESS_MSG,
                                              f'{self.remote_excute} = on')
        self.log.info(set_param1)
        self.assertTrue(set_param1, 'remote_excute设置失败')

        set_param2 = Primary_SH.execute_gsguc('set',
                                              self.constant.GSGUC_SUCCESS_MSG,
                                              f'{self.bcast_snapshot} = on')
        self.log.info(set_param2)
        self.assertTrue(set_param2, 'bcast_snapshot设置失败')

        stop = Primary_SH.exec_cm_ctl('stop')
        self.log.info(stop)
        start = Primary_SH.exec_cm_ctl('start')
        self.log.info(start)

        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cv')
        self.log.info(status)
        self.assertIn('cluster_state   : Normal', status, '执行失败' + text)

        text = '-----step3:设置dn僵死重启时间 expect:设置成功-----'
        self.log.info(text)

        cm_param = Primary_SH.exec_cm_ctl('set', '--param --server',
                                          f'-k {self.param}="10"')
        self.log.info(cm_param)
        self.assertIn(self.constant.cm_set_param_success_msg, cm_param, '参数设置失败')
        cm_reload = Primary_SH.exec_cm_ctl('reload', '--param --server')
        self.log.info(cm_reload)
        self.assertIn(self.constant.cm_reload_success_msg, cm_reload, '参数reload失败')

        text = '-----step4:挂起主节点dn进程; expect:成功-----'
        self.log.info(text)

        pri_dn_pid1 = self.com.get_pid(self.usernode, 'bin/gaussdb')
        self.log.info(pri_dn_pid1)
        kill_dn = self.usernode.sh(f'kill -19 {pri_dn_pid1}').result()
        self.log.info(kill_dn)

        process = f"ps ux | grep -v grep | grep 'bin/gaussdb' | awk '{{{{print$8}}}}' "
        res1 = self.usernode.sh(process).result()
        self.log.info(res1)
        self.assertIn('', kill_dn, '进程存在')
        self.assertIn('Tl', res1, '进程挂起失败')

        text = '-----step5:再次查看dn进程,观察CMS服务是否会自动拉起恢复dn,查看集群状态; ' \
               'expect:dn进程存在,dn进程状态正常,集群状态异常-----'
        self.log.info(text)

        time.sleep(180)
        pri_dn_pid2 = self.com.get_pid(self.usernode, 'bin/gaussdb')
        self.log.info(pri_dn_pid2)

        res2 = self.usernode.sh(process).result()
        self.log.info(res2)
        self.assertNotEqual(pri_dn_pid1, pri_dn_pid2, '主节点dn进程号一致')
        self.assertIn('Sl', res2, '进程状态正常')

    def tearDown(self):
        text = '-----step6:恢复环境为初始集群状态; expect:成功-----'
        self.log.info(text)

        time.sleep(30)
        self.log.info('---恢复参数默认值---')
        set_param3 = Primary_SH.execute_gsguc('set',
                                              self.constant.GSGUC_SUCCESS_MSG,
                                              f'{self.remote_excute} = {self.remote_excute_default}')
        self.log.info(set_param3)

        set_param4 = Primary_SH.execute_gsguc('set',
                                              self.constant.GSGUC_SUCCESS_MSG,
                                              f'{self.bcast_snapshot} = {self.bcast_snapshot_default}')
        self.log.info(set_param4)

        self.log.info('---重启集群---')
        stop = Primary_SH.exec_cm_ctl('stop')
        self.log.info(stop)
        start = Primary_SH.exec_cm_ctl('start')
        self.log.info(start)

        self.log.info('---查看集群状态---')
        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cv')
        self.log.info(status)
        p_status = status.splitlines()[-1].split('|')[0].split('6001')[-1]
        if 'Primary' in p_status:
            self.log.info('---集群状态正常，无需恢复为初始状态---')
        else:
            recovery = Primary_SH.exec_cm_ctl(mode='switchover', param='-a')
            self.log.info(recovery)

            self.assertIn(self.constant.cm_switchover_success_msg, recovery,
                          '执行失败' + text)

        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cv')
        self.log.info(status)

        self.assertIn('cluster_state   : Normal', status, '执行失败' + text)
        self.assertIn('P Primary Normal',
                      status.splitlines()[-1].split('|')[0].split('6001')[-1],
                      '执行失败' + text)
        self.assertIn('S Standby Normal',
                      status.splitlines()[-1].split('|')[1].split('6002')[-1],
                      '执行失败' + text)
        self.log.info(f'-----{os.path.basename(__file__)} end-----')
